#include "OBJLoader.h"

//ifstream used to open and parse the files
#include <iostream>

#include "Globals.h"

OBJLoader::OBJLoader()
{}

OBJLoader::~OBJLoader()
{}

void OBJLoader::SkipWhiteSpace(std::ifstream &fin)
{
	while(1)
	{
		//Peek char
		char c = fin.peek();

		//If character is not a space, extract it (ignoring it)
		//else return. 
		if ( (c != ' ') || (fin.eof()) )
			return;
		else
		{
			//Extract this character.
			char ignore[1];
			fin.read(ignore, 1);
		}
	}
}

void OBJLoader::SkipLine(std::ifstream &fin)
{
	while(1)
	{
		//Peek character (Doesnt extract)
		char c = fin.peek();
		char ignore[1];

		//Extract this character.
		fin.read(ignore, 1);

		//if this is a new line, we are done (note we also
		//skip the new line character.
		if ( (c == '\n') || (fin.eof()) )
			return;
	}
}

void OBJLoader::OutputChar(char c, bool newLine)
{
	std::string str;
	str.resize(1);
	str[0] = c;

	OutputDebugStringA(str.c_str());

	if (newLine)
		OutputDebugStringW(L"\n");
}

void OBJLoader::OutputString(std::string str, bool newLine)
{
	OutputDebugStringA(str.c_str());

	if (newLine)
		OutputDebugStringW(L"\n");
}

void OBJLoader::OutputInt(int i, bool newLine)
{
	std::stringstream ss;
	ss << i;
	OutputString(ss.str(), newLine);
}

void OBJLoader::OutputFloat(float f, bool newLine)
{
	std::stringstream ss;
	ss << f;
	OutputString(ss.str(), newLine);
}

std::wstring OBJLoader::ToWS(std::string s)
{
    int len;
    int slength = (int)s.length() + 1;
    len = MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, 0, 0); 
    wchar_t* buf = new wchar_t[len];
    MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, buf, len);
    std::wstring r(buf);
    delete[] buf;
    return r;
}

//
//Main
//

void OBJLoader::LoadOBJ(ID3D11Device* device,       //VB creation etc.
		StaticModel* mod,							//OBJ Loader will init vb, ib and materials.
		LPCWSTR objFilePath,						//.obj file path inc .obj
		std::vector<LPCWSTR> &objMaterialFilePath,  //Array of .mtl files
		std::string textureFolderPath,				//File path of where the textures are located
		bool useDispMapping,						//Are we going to render this with disp mapping where possible?
		TessellationData* tessData,			        //If useDispMapping == true, this sets tessellation factors
		XMFLOAT2 texScale)							//Texture scaling.
{
	OutputDebugStringW(L"LoadOBJ() : ");
	OutputDebugStringW(objFilePath);
	OutputDebugStringW(L"\n");

	//Parse .mtl files (Materials)
	for (unsigned i = 0; i < objMaterialFilePath.size(); i++)
		ParseMaterialMain(objMaterialFilePath[i]);

	//Parse .obj file (Vertex/Index data)
	ParseOBJMain(objFilePath, textureFolderPath, device); 

	//We now have all the data we need to create the static model. We will have one
	//StaticModel::subModels entry per OBJSubModel entry here. 
	for (unsigned i = 0; i < objSubModels.size(); i++)
	{
		//Will be pushed back on StaticModel::subModels vector.
		StaticModel::SubModelData* smd = new StaticModel::SubModelData();
		//Reference to this submodels objMaterial.
		OBJMaterial& objM = (*objSubModels[i].ObjMaterial);
		//Referece to this subModel
		OBJSubModel& objSm = objSubModels[i];
		//Lighting material strucut (reflectivity)
		Material mat;

		//Copy reflectivity material across to Material struct. 
		mat.Ambient = XMFLOAT4(objM.Ka.x, objM.Ka.y, objM.Ka.z, 1.0f);
		mat.Diffuse = objM.Kd;
		mat.Specular = objM.Ks;

		//Copy data in to smd.
		smd->DrawCount = objSm.VertexCount;
		smd->HeightMap = 0;
		smd->ib = objSm.IB;

		if (objM.Kd.w == 1.0f)
			smd->IsOpaque = true;
		else
			smd->IsOpaque = false;
		
		//smd->IsUsingDisplacementMapping = useDispMapping;
		smd->IsUsingDisplacementMapping = false;
		smd->IsUsingSeperateHeightMap = false;
		smd->Mat = mat;
		smd->NormalMap = objSm.NormalMap;
		smd->StartDrawIndex = objSm.VertexStart;

		if (tessData)
			smd->TessData = (*tessData);

		XMMATRIX ts = XMMatrixScaling(texScale.x, texScale.y, 1.0f);
		XMStoreFloat4x4(&smd->TexTrans, ts);

		smd->TextureMap = objSm.TextureMap;
		smd->Topology = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
		smd->vb = objSm.VB;

		mod->subModels.push_back(smd);
	}

	//Create AABB - Read position data from the OBJ loader in to the
	//StaticModel::systemVertexCopyArr
	mod->systemVertexCopyArr.assign(vertPos.begin(), vertPos.end());
	mod->CreateAABB();

	OutputDebugStringW(L"Finished Loading OBJ : ");
	OutputDebugStringW(objFilePath);
	OutputDebugStringW(L"\n");
}

//
//Parse .mtl
//

void OBJLoader::ParseMaterialMain(LPCWSTR objMaterialFilePath)
{
	OutputDebugStringW(L"ParseMaterialMain() : ");
	OutputDebugStringW(objMaterialFilePath);
	OutputDebugStringW(L"\n");

	//Open .mtl file. 
	std::ifstream fin(objMaterialFilePath);

	if (fin)
	{
		while(!fin.eof())
		{
			//Read text untill a space. 
			std::string toTest = "";
			fin >> toTest;

			//We have a comment which can be skipped. 
			if (toTest.compare("#") == 0)
				SkipLine(fin);
			//A new material definition
			else if (toTest.compare("newmtl") == 0)
				LoadNewMaterial(fin);
			//Anything else - eg a new line. 
			else
				SkipLine(fin); 
		}

		//Close file
		fin.close();
	}
	else
	{
		OutputDebugStringW(L"OBJLoader Error - Can not open material file...\n");
		while(1){}
	}

	OutputDebugStringW(L"Finished parsing : ");
	OutputDebugStringW(objMaterialFilePath);
	OutputDebugStringW(L"\n");
}

void OBJLoader::LoadNewMaterial(std::ifstream &fin)
{
	OutputDebugStringW(L"LoadNewMaterial() : ");

	//Read in to this string.
	std::string str = "";

	//New material
	OBJMaterial m;

	//Read title. 
	SkipWhiteSpace(fin);
	fin >> str;
	m.MaterialName = str;
	SkipLine(fin);

	OutputString(m.MaterialName, false);
	OutputDebugStringW(L"\n");

	//Loop until we find EOF, # or newmtl
	while(1)
	{
		//Read in new component of the material. 
		str = "";
		fin >> str;

		//EOF or we are to parse a new material. (Comments
		//are automatically skipped)
		if ( (str.compare("newmtl") == 0) || (fin.eof()) )
		{
			//put back chars
			for (unsigned i = str.size(); i > 0; i--)
				fin.putback(str[i-1]);
			//Break loop
			break;
		}
		else if (str.compare("Ka") == 0)
		{
			SkipWhiteSpace(fin);
			fin >> m.Ka.x;
			SkipWhiteSpace(fin);
			fin >> m.Ka.y;
			SkipWhiteSpace(fin);
			fin >> m.Ka.z;
			SkipLine(fin);
		}
		else if (str.compare("Kd") == 0)
		{
			SkipWhiteSpace(fin);
			fin >> m.Kd.x;
			SkipWhiteSpace(fin);
			fin >> m.Kd.y;
			SkipWhiteSpace(fin);
			fin >> m.Kd.z;
			SkipLine(fin);
		}
		else if (str.compare("Ks") == 0)
		{
			SkipWhiteSpace(fin);
			fin >> m.Ks.x;
			SkipWhiteSpace(fin);
			fin >> m.Ks.y;
			SkipWhiteSpace(fin);
			fin >> m.Ks.z;
			SkipLine(fin);
		}
		else if (str.compare("Ns") == 0)
		{
			SkipWhiteSpace(fin);
			fin >> m.Ks.w;
			SkipLine(fin);
		}
		else if ((str.compare("d") == 0) || (str.compare("Tr") == 0) )
		{
			SkipWhiteSpace(fin);
			fin >> m.Kd.w;
			SkipLine(fin);
		}
		else if (str.compare("map_Kd") == 0)
		{
			m.UseDiffuseMap = true;
			SkipWhiteSpace(fin);
			fin >> m.DiffuseMapName;
			SkipLine(fin);
		}
		else if ( (str.compare("map_bump") == 0) || (str.compare("bump") == 0) )
		{
			m.UseNormalMap = true;
			SkipWhiteSpace(fin);
			fin >> m.NormalMapName;
			SkipLine(fin);
		}
		else if (str.compare("illum") == 0)
			//Not yet supported
			SkipLine(fin);
		else
			SkipLine(fin);
	}

	//Push new material on to material structure.
	objMats.push_back(m);
}

//
//Parse .obj
//

void OBJLoader::ParseOBJMain(LPCWSTR objFilePath, std::string texFile, ID3D11Device* device)
{
	OutputDebugStringW(L"ParseOBJMain() : ");
	OutputDebugStringW(objFilePath);
	OutputDebugStringW(L"\n");

	//Open file
	std::ifstream fin(objFilePath);

	if (fin)
	{
		while(!fin.eof())
		{
			//String to read in to
			std::string toTest = "";
			//Read a string or character (eg, # or usemtl, etc)
			fin >> toTest;

			//A comment - we can skip
			if (toTest.compare("#") == 0)
				SkipLine(fin);
			//Tells us to load a certain mtl file. We can ignore
			//this as we handle this differntly. 
			else if (toTest.compare("mtllib") == 0)
				SkipLine(fin);
			//Vertex position
			else if (toTest.compare("v") == 0)
				ParseVertexPosition(fin);
			//Vertex tex coord
			else if (toTest.compare("vt") == 0)
				ParseVertexTex(fin);
			//Vertex normal vector
			else if (toTest.compare("vn") == 0)
				ParseVertexNormal(fin);
			//Indicates that we are begining to load index data for a submodel/material
			else if (toTest.compare("usemtl") == 0)
				ParseSubModel(fin, texFile, device);
			//else, something that isnt supported or can be ignored
			else
				SkipLine(fin);
		}
	}
	else
	{
		OutputDebugStringW(L"OBJ Loader Error - Can not open .obj file\n");
		while(1){}
	}

	OutputDebugStringW(L"Finished parsing : ");
	OutputDebugStringW(objFilePath);
	OutputDebugStringW(L"\n");
}

void OBJLoader::ParseVertexPosition(std::ifstream &fin)
{
	//Read in to this structure. 
	XMFLOAT3 data;

	//Skip and read in.
	SkipWhiteSpace(fin);
	fin >> data.x;
	SkipWhiteSpace(fin);
	fin >> data.y;
	SkipWhiteSpace(fin);
	fin >> data.z;
	
	//Skip the rest of the line
	SkipLine(fin);

	//Push data in to vector
	vertPos.push_back(data);

	//OutputDebugStringW(L"ParseVertexPosition()\n");
}

void OBJLoader::ParseVertexTex(std::ifstream &fin)
{
	//Read data in to this struct
	XMFLOAT2 data;

	//Skip and read in.
	SkipWhiteSpace(fin);
	fin >> data.x;
	SkipWhiteSpace(fin);
	fin >> data.y;

	//Skip rest of line
	SkipLine(fin);

	//Push on to tex coord vector
	vertTex.push_back(data);

	//OutputDebugStringW(L"ParseVertexTex()\n");
}

void OBJLoader::ParseVertexNormal(std::ifstream &fin)
{
	//Read data in to this struct
	XMFLOAT3 data;

	//Skip white space and read in data
	SkipWhiteSpace(fin);
	fin >> data.x;
	SkipWhiteSpace(fin);
	fin >> data.y;
	SkipWhiteSpace(fin);
	fin >> data.z;

	//Skip rest of the line
	SkipLine(fin);

	//Push on to normal vector vector
	vertNorm.push_back(data);

	//OutputDebugStringW(L"ParseVertexNormal()\n");
}

void OBJLoader::ParseSubModel(std::ifstream &fin, std::string texFile, ID3D11Device* device)
{
	//The material will indicate if are applying any textures. 
	bool isUsingTex = false;
	bool isUsingBump = false;

	//Store the material name.
	std::string matName = "";
	SkipWhiteSpace(fin);
	fin >> matName;

	//Make sure material exists with this name and get pointer to it.
	OBJMaterial* m = 0;
	for (unsigned i = 0; i < objMats.size(); i++)
		if (matName.compare(objMats[i].MaterialName) == 0)
			m = &objMats[i];

	//If m is null, no material was found. Print error and enter loop
	if (!m)
	{
		OutputDebugStringW(L"OBJLoader Error - Trying to use a material that has not been loaded...\n");
		while(1){}
	}

	OutputDebugStringW(L"ParseSubModel(): Material: ");
	OutputString(matName, true);

	//Vectors which will hold our vertex data for this submodel. Eventually,
	//there will be one entry per vertex for this submodel. 
	//
	//For each of the below vectors, the ith entry is the ith vertex. Thus, 
	//if a vertex has position, tex and normal data, the data for the 5th vertex
	//can be found by indexing in to these 3 vectors at index 4 (Because we start at
	//0)
	std::vector<XMFLOAT3>subModelPositions;
	std::vector<XMFLOAT2>subModelTex;
	std::vector<XMFLOAT3>subModelNorm;
	std::vector<XMFLOAT4>subModelTang;

	//Are we using textures? If using normal map, then we will
	//be generating tangent vectors. Note: If we do not have 
	//normal data, we will have to create that too. 
	if (m->UseDiffuseMap)
		isUsingTex = true;
	if (m->UseNormalMap)
		isUsingBump = true;

	//Pase the submodel. - Some data in here may not be face data (eg comments)
	//so we need a method to ignore these lines. ParseFace() parses an individual
	//face line. (F 23/42/41 23/32/12 235/533/41)
	while (!fin.eof())
	{
		//Read in to the string...
		std::string toRead = "";
		fin >> toRead;

		//New material being parsed - Read back, break loop, create vb data
		//and then return back to main (Which then will get back to here...)
		if (toRead.compare("usemtl") == 0)
		{
			//Read string back in to fin.
			for (unsigned i = toRead.size(); i > 0; i--)
				fin.putback(toRead[i-1]);

			//Break loop as we have the data for this submodel
			break;
		}
		//Not supported features. 
		else if (toRead.compare("s") == 0)
			SkipLine(fin);
		else if (toRead.compare("o") == 0)
			SkipLine(fin); 
		else if (toRead.compare("g") == 0)
			SkipLine(fin);
		else if (toRead.compare("f") == 0)
			ParseFace(fin, m, subModelPositions, subModelTex, subModelNorm);
		//More vertex data. 
		else if ( (toRead.compare("v") ==  0) || (toRead.compare("vt") == 0) || 
				  (toRead.compare("vn") == 0) )
		{
			//Read string back in to fin.
			for (unsigned i = toRead.size(); i > 0; i--)
				fin.putback(toRead[i-1]);

			//Break loop
			break;
		}
		else
			SkipLine(fin);
	}//End while (!fin.eof())

	//No have all the vertex data for this submodel so we can create the VB
	//(OBJSubModel::VB), load textures, set vertex count and set the OBJMaterial
	//pointer within the OBJSubModel for later use.
	//
	//Firstly, generate our tangent vectors if normal mapping will be
	//used for this submodel.
	if (m->UseNormalMap)
	{
		OutputDebugStringW(L"Generating Tangent Vectors\n");
		OutputDebugStringW(L"TO DO...\n");
		while(1){}
		GenTangentVectors(subModelPositions, subModelNorm, subModelTex, subModelTang, 
			subModelPositions.size());
	}

	//Create OBJSubModel
	LoadNewOBJSubModel(device, m, texFile,
		subModelPositions, subModelTex, subModelNorm, subModelTang);
}

void OBJLoader::ExtractVertexData(std::string &str, int &posIndex, int &texIndex, int &normIndex)
{
	//Read individual vertex data in to this - convert
	//to an int later. 
	std::string temp = "";

	//Number of chars extracted from the string.
	int loopCounter = 0;

	//Position
	while(1)
	{
		//look at the char at index loopCounter
		char c = str[loopCounter];

		//Increment loopCounter
		loopCounter++;

		if (c != '/')
			//Extract to a temp string
			temp += c;
		//If it is /, break the loop.
		else
			break;
	}

	//Convert this to an int and store. 
	posIndex = atoi(temp.c_str());
	//Reset temp
	temp = "";

	//Similar for texture coordinate data - however this is optional. 
	//we should see // if no data is present. (Actually, we should see
	//just a single '/' since the first '/' is skipped above. 
	while(1)
	{
		//look at the char at index loopCounter. Note that this loop
		//counter carries on 
		//
		//If we have reached the end of the string (ie, no normal data)
		//then break the loop. 
		if (loopCounter >= (int)str.size())
			break;
		char c = str[loopCounter];

		//Again, increment loopCounter.
		loopCounter++;

		if (c != '/')
			temp+=c;
		else
			break;
	}

	//Convert to an int and store if size >= 1
	if (temp.size() >= 1)
		texIndex = atoi(temp.c_str());
	//Reset temp 
	temp = "";

	//Normal data. Again, optional. if loop counter > 
	//str.size(), then we dont have any normal data. 
	while (1)
	{
		//look at the char at index loopCounter. Note that this loop
		//counter carries on 
		//
		//If we have reached the end of the string (ie, no normal data)
		//then break the loop. 
		if (loopCounter >= (int)str.size())
			break;
		char c = str[loopCounter];

		//Again, increment loopCounter.
		loopCounter++;

		if (c != '/')
			temp+=c;
		else
			break;
	}

	//Convert to an int and store.
	if (temp.size() >= 1)
		normIndex = atoi(temp.c_str());

	//Output indicies...
	//OutputInt(posIndex);
	//OutputDebugStringW(L"/");
	//OutputInt(texIndex);
	//if (normIndex != -1)
	//{
	//	OutputDebugStringW(L"/");
	//	OutputInt(normIndex);
	//}
	//OutputDebugStringW(L"\n");
}

void OBJLoader::LoadNewOBJSubModel(ID3D11Device* device, OBJMaterial* m, std::string texFile, 
		std::vector<XMFLOAT3>&subModelPositions,
		std::vector<XMFLOAT2>&subModelTex,
		std::vector<XMFLOAT3>&subModelNorm,
		std::vector<XMFLOAT4>&subModelTang)
{
	//Fillout the OBJSubModel structure for this submodel. 
	OBJSubModel mod;
	
	//Set material pointer.
	mod.ObjMaterial = m;
	mod.VertexStart = 0;
	mod.VertexCount = subModelPositions.size();

	//Load texture map?
	if (m->UseDiffuseMap)
	{
		//Create full file path
		std::string filePath = texFile;
		filePath+=m->DiffuseMapName;

		//Convert to wstring - .c_str converts to LPCWSTR
		std::wstring file = ToWS(filePath);

		//Load the texture map. 
		HR(D3DX11CreateShaderResourceViewFromFile(device, 
			file.c_str(), 0,0,&mod.TextureMap, 0));
	}

	//Load normal map?
	if (m->UseNormalMap)
	{
		//Create full file path
		std::string filePath = texFile;
		filePath+=m->NormalMapName;

		//Convert to wstring - .c_str converts to LPCWSTR
		std::wstring file = ToWS(filePath);

		//Load the texture map. 
		HR(D3DX11CreateShaderResourceViewFromFile(device, 
			file.c_str(), 0,0,&mod.NormalMap, 0));
	}

	//Decide which vertex structure we have and load the data across. 
	std::vector<TileForwardNormalMapFX::PosNormalTexTangentVertex>pntt;
	std::vector<TileForwardTextureMapFX::PosNormalTexVertex>pnt;
	std::vector<TileForwardSolidColourFX::PosNormalVertex>pn;

	//Byte width of the vertex bufffer.
	unsigned totByteWidthOfVB = 0;

	if(m->UseNormalMap)
	{
		//Resize vector.
		pntt.resize(subModelPositions.size());

		//Extract: Position, normal, tex and tangent (xyz) data.
		for (unsigned i = 0; i < subModelPositions.size(); i++)
		{
			XMFLOAT3 t = XMFLOAT3(subModelTang[i].x, subModelTang[i].y, subModelTang[i].z);

			pntt[i].PosL = subModelPositions[i];
			pntt[i].NormalL = subModelNorm[i];
			pntt[i].Tex = subModelTex[i];
			pntt[i].TangentL = t;
		}

		//Work out byte width.
		totByteWidthOfVB = sizeof(TileForwardNormalMapFX::PosNormalTexTangentVertex) * pntt.size();
	}
	else if (m->UseDiffuseMap)
	{
		//Resize vector.
		pnt.resize(subModelPositions.size());

		//Extract Position, normal, tex data.
		for (unsigned i = 0; i < subModelPositions.size(); i++)
		{
			pnt[i].PosL = subModelPositions[i];
			pnt[i].NormalL = subModelNorm[i];
			pnt[i].Tex = subModelTex[i];
		}

		//Work out byte width.
		totByteWidthOfVB = sizeof(TileForwardTextureMapFX::PosNormalTexVertex) * pnt.size();
	}
	else
	{
		//Resize vector.
		pn.resize(subModelPositions.size());

		//Extract Position and normal data only.
		for (unsigned i = 0; i < subModelPositions.size(); i++)
		{
			pn[i].PosL = subModelPositions[i];
			pn[i].NormalL = subModelNorm[i];
		}

		//Work out byte width.
		totByteWidthOfVB = sizeof(TileForwardSolidColourFX::PosNormalVertex) * pn.size();
	}

	//Create VB.
	D3D11_BUFFER_DESC bd;
	D3D11_SUBRESOURCE_DATA sd;

	bd.BindFlags = D3D11_BIND_VERTEX_BUFFER; 
	bd.CPUAccessFlags = 0;
	bd.MiscFlags = 0;
	bd.StructureByteStride = 0;
	bd.Usage = D3D11_USAGE_IMMUTABLE;
	bd.ByteWidth = totByteWidthOfVB;

	if(m->UseNormalMap)
		sd.pSysMem = &pntt[0];
	else if (m->UseDiffuseMap)
		sd.pSysMem = &pnt[0];
	else 
		sd.pSysMem = &pn[0];

	HR(device->CreateBuffer(&bd, &sd, &mod.VB));

	//Push filledout OBJSubModel struct on to the vector.
	objSubModels.push_back(mod);
}

void OBJLoader::ParseFace(std::ifstream &fin, OBJMaterial* objM, 
		std::vector<XMFLOAT3>&subModelPositions,
		std::vector<XMFLOAT2>&subModelTex,
		std::vector<XMFLOAT3>&subModelNorm)
{
	//Face - parse: v/vt/vn || v/vt || v//vn
	//OutputDebugStringW(L"Parse Face\n");

	//Bool indicating if normal data has been generated. 
	bool hasNormalBeenExtracted = false;

	//Skip to first vertex.
	SkipWhiteSpace(fin);

	//Extract data (vertex data) to in 3 strings. Each represneting
	//one vertex of the traingle. Eg: 3/2/1 2/2/1 2/5/5. We read 
	//"3/2/1" in to one string, "2/2/1" in to another, and then
	//"2/5/5" in to another (With the /). 
	std::string vData[3] = {"", "", ""};
	fin >> vData[0];
	SkipWhiteSpace(fin);
	fin >> vData[1];
	SkipWhiteSpace(fin);
	fin >> vData[2];

	//Skip the rest of the line
	SkipLine(fin);

	//With the data stored in the strings (eg: 
	//"3/2/1", we need to work out what data
	//we have (vertex and texture and/or normal)
	//
	//And then we need to use the individual numbers
	//to extract data from our stored list of vertex
	//data. 
	for (unsigned i = 0; i < 3; i++)
	{
		//Used to index in to the stored vectors of vertex
		//data. -1 indicates that we should not index. 
		int posIndex = -1;
		int texIndex = -1;
		int normIndex = -1;

		//Copy the vertex data we are concerned with. 
		std::string str = vData[i];

		//Extract the individual components from this string. - reutrns the
		//index which will be used to index in to our global vectors
		//of vertex data
		ExtractVertexData(str, posIndex,texIndex, normIndex);

		//Remember to subtract one since the index in side the obj
		//begins at 1 whereas arrays/vectors in code begins at 0.
		//
		//Must have position data.
		subModelPositions.push_back(vertPos[posIndex-1]);
		//Only if tex data is available...
		if ( (texIndex != -1) && (objM->UseDiffuseMap) )
			subModelTex.push_back(vertTex[texIndex-1]);
		//If no normal index is provided, we need to create one later. 
		if (normIndex != -1)
		{
			//Normal data exists - set flag.
			hasNormalBeenExtracted = true;
			//Store normal vector.
			subModelNorm.push_back(vertNorm[normIndex-1]);
		}
	}//End for (i)

	//We now parsed a face (polly) - therefore, we can work out
	//the normal vectors if not present and work out
	//the tangent vector if required.
	if (!hasNormalBeenExtracted) //!hasNormalBeenExtracted
	{
		//(Assumes that the verticies are exported in anti-clockwise order
		//subModelNorm.push_back(GenNormalVector(pos[0], pos[1], pos[2]));
		//subModelNorm.push_back(GenNormalVector(pos[1], pos[2], pos[0]));
		//subModelNorm.push_back(GenNormalVector(pos[2], pos[0], pos[1]));

		//Note: For the time being, we just crash the application if the .obj
		//doesnt contain normal vectors
		OutputDebugStringW(L"OBJLoader - File does not contain normal data. Can not create accuratly\n");
		while(1){}
	}
}

XMFLOAT3 OBJLoader::GenNormalVector(XMFLOAT3 a, XMFLOAT3 b, XMFLOAT3 c)
{
	//OutputDebugStringW(L"GenNormalVector()\n");
	//Load input to XMVECTORS. 
	XMVECTOR p1, p2, p3;
	p1 = XMLoadFloat3(&a);
	p2 = XMLoadFloat3(&b);
	p3 = XMLoadFloat3(&c);

	//Work out normal vector and normalize
	XMVECTOR norm = XMVector3Normalize(XMVector3Cross((p2-p1), (p3-p1)));
	
	//store in to XMFLOAT3 and return
	XMFLOAT3 n;
	XMStoreFloat3(&n, norm);

	return n;
}

void OBJLoader::GenTangentVectors(std::vector<XMFLOAT3>&pos,
		std::vector<XMFLOAT3>&norm, 
		std::vector<XMFLOAT2>&tex, 
		std::vector<XMFLOAT4>&tangOut, 
		long vertexCount)
{

}